﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace MTViewer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ITouchObject _picture;
        private Point _prevLocation;
        private int _lastZIndex = 1;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            //close connection
            App.DbManager.Connect();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //open connectoin
            App.DbManager.Connect();
            
            //Initialize child controls
            TouchObjectFactory.CanvasInstance = _canvas;

            dbPanel.SetDragDropImage(dragDropImage);

            dbPanel.AddDropDrawingEventHandler((src, a) =>
                    {
                        AddNewObjectToCanvas(a.DrawingFileName, a.PdfDrawingFileName, a.DgnDrawingFileName, a.Position, Properties.Settings.Default.DefaultDrawingWidth, 0);
                    }
                );
        }

        #region mouse events

        private void ProcessDown(object sender, MouseButtonEventArgs args)
        {
            _prevLocation = args.GetPosition(_canvas);
            Debug.WriteLine(" MousePoint:"+ _prevLocation);

            _picture = FindObject(_prevLocation);
            BringObjectToFront(_picture);
        }

        private void ProcessMove(object sender, MouseEventArgs args)
        {
            if (args.LeftButton == MouseButtonState.Released || _picture == null)
                return;
            Point newLocation = args.GetPosition(_canvas);

            _picture.X += newLocation.X - _prevLocation.X;
            _picture.Y += newLocation.Y - _prevLocation.Y;

            Debug.WriteLine(" MouseMove:" + _picture.X + "  " + _picture.GetType().Name);
            _prevLocation = newLocation;
        }

        private void ProcessUp(object sender, MouseButtonEventArgs args)
        {
            _picture = null;
        }

        private void ProcessMouseWheel(object sender, MouseWheelEventArgs args)
        {
            Point location = args.GetPosition(_canvas);
            ITouchObject picture = FindObject(location);

            if (picture != null)
            {
                BringObjectToFront(picture);

                double scalingFactor = 1 + args.Delta / 1000.0;
                picture.ScaleX *= scalingFactor;
                picture.ScaleY *= scalingFactor;
            }
        }

        #endregion

        #region supplement code

        private void AddNewObjectToCanvas(string fileName, string pdfFileName, string dgnFileName, Point position, int width, int angle)
        {
            ITouchObject p = TouchObjectFactory.CreateTouchObject(fileName);
            
            p.DgnFileName = dgnFileName;
            p.PdfFileName = pdfFileName;
            p.Angle = angle;
            p.X = position.X;
            p.Y = position.Y;
            
            //set width if its possible
            if ((p as Picture)!= null)
            { 
                p.Width = width;
            }

            //attach extra handler
            p.OnCreateControl += new EventHandler<PIBV.LoadDrawingEventArgs>(OnCreateCauseEffectControl);

            _canvas.Children.Add((UIElement)p);

            BringObjectToFront(p);
        }

        void OnCreateCauseEffectControl(object sender, PIBV.LoadDrawingEventArgs e)
        {
            AddNewObjectToCanvas(e.DrawingFileName, 
                                 e.PdfDrawingFileName,
                                 e.DgnDrawingFileName,
                                 new Point(Convert.ToInt32((sender as ctrlCapMatrix).GetValue(ctrlCapMatrix.XProperty)), 
                                 Convert.ToInt32((sender as ctrlCapMatrix).GetValue(ctrlCapMatrix.YProperty))),
                                 Convert.ToInt32((sender as ctrlCapMatrix).GetValue(ctrlCapMatrix.ActualWidthProperty)) * Convert.ToInt32((sender as ctrlCapMatrix).GetValue(ctrlCapMatrix.ScaleXProperty)), 
                                 Convert.ToInt32((sender as ctrlCapMatrix).GetValue(ctrlCapMatrix.AngleProperty)));
        }

        /// <summary>
        /// Find the picture in the touch location
        /// </summary>
        /// <param name="pointF">touch location</param>
        /// <returns>The picture or null if no picture exists in the touch location</returns>
        private ITouchObject FindObject(Point location)
        {
            ITouchObject findedObj = null;
            HitTestResult result = VisualTreeHelper.HitTest(_canvas, location);

            if(result!=null)
            {
                Image image = result.VisualHit as Image;

                if (image != null)
                {
                    findedObj = image.Parent as ITouchObject;
                }
                else
                {
                    findedObj = FindITouchObject(result.VisualHit);
                }
            }

            return findedObj;
        }

        ITouchObject FindITouchObject(DependencyObject elem)
        {
            ITouchObject result = null;
            FrameworkElement ctrl = elem as FrameworkElement;
            if (elem!=null && ctrl != null)
            {
                result = ctrl as ITouchObject;

                if (result == null)
                {
                    result = FindITouchObject(VisualTreeHelper.GetParent(ctrl));
                }
            }
            
            return result;
        }

        private void BringObjectToFront(ITouchObject picture)
        {
            if (picture != null)
            {
                _lastZIndex++;
                Canvas.SetZIndex((UIElement)picture, _lastZIndex);
                //dropDownImage should be always topmost
                Canvas.SetZIndex((UIElement)dragDropImage, _lastZIndex+1);
            }
            //if (picture == null)
            //    return;

            //var children = (from UIElement child in _canvas.Children
            //                where child != picture
            //                orderby Canvas.GetZIndex(child)
            //                select child).ToArray();

            //for (int i = 0; i < children.Length; ++i)
            //{
            //    Canvas.SetZIndex(children[i], i);
            //}
            //Canvas.SetZIndex((UIElement)picture, children.Length);
        }

        private void dbPanel_GotFocus(object sender, RoutedEventArgs e)
        {
            _lastZIndex++;
            Canvas.SetZIndex((UIElement)dbPanel, _lastZIndex);
            //dropDownImage should be always topmost
            Canvas.SetZIndex((UIElement)dragDropImage, _lastZIndex + 1);
        }

        #endregion

        private void Window_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            Point pointFromScreen = (e.OriginalSource as FrameworkElement).PointToScreen(e.ManipulationOrigin);
            ITouchObject p = FindObject(pointFromScreen);
            BringObjectToFront(p);
        }

        private void _canvas_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            Point pointFromScreen = (e.OriginalSource as FrameworkElement).PointToScreen(e.ManipulationOrigin);
            ITouchObject p = FindObject(pointFromScreen);

            if (p != null)
            {
                ManipulationDelta md = e.DeltaManipulation;
                p.X += md.Translation.X;
                p.Y += md.Translation.Y;
                p.Angle += md.Rotation;
                p.ScaleX *= md.Scale.X;
                p.ScaleY *= md.Scale.Y;
            }

            e.Handled = true;
        }

        private void _canvas_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {
            e.TranslationBehavior = new InertiaTranslationBehavior()
            {
                InitialVelocity = e.InitialVelocities.LinearVelocity,
                DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0),
            };

            e.RotationBehavior = new InertiaRotationBehavior()
            {
                InitialVelocity = e.InitialVelocities.AngularVelocity,
                DesiredDeceleration = 10 / (1000 * 1000),
            };

            e.Handled = true;
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                App.Current.Shutdown();
            }
        }

        private void _canvas_Drop(object sender, DragEventArgs e)
        {
            PIBV.LoadDrawingEventArgs result = e.Data.GetData(typeof(PIBV.LoadDrawingEventArgs)) as PIBV.LoadDrawingEventArgs;
            if (result != null && !String.IsNullOrEmpty(result.DrawingFileName))
            {
                AddNewObjectToCanvas(result.DrawingFileName, result.PdfDrawingFileName, result.DgnDrawingFileName,e.GetPosition(_canvas), Properties.Settings.Default.DefaultDrawingWidth, 0);
            }
        }

    }
}
